package fr.ajicommerce.core.dao.generics;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component("genericDAO")
@Transactional
public abstract class GenericDAO<T, PK> implements AbstractDAO<T, PK> {

	Logger log = Logger.getLogger(getClass());

	protected EntityManager em;

	@PersistenceContext(unitName = "entityManagerFactory")
	public void setEntityManager(EntityManager entityManager) {
		this.em = entityManager;
	}

	private Class<T> entityClass;

	public GenericDAO(Class<T> entityClass) {
		this.entityClass = entityClass;
	}

	@Override
	public T merge(T entity) {
		return em.merge(entity);
	}
	
	@Override
	public void save(T entity) {
		em.persist(entity);
		em.flush();
	}

	@Override
	public void delete(T entity) {
		T toRemoved = em.merge(entity);
		em.remove(toRemoved);
	}

	@Override
	public T update(T entity) {
		return em.merge(entity);
	}

	@Override
	public T find(Long entityID) {
		System.out.println("Find Identifiant  :" + entityID);
		System.out.println("Of class :" + entityClass.getSimpleName());
		System.out.println("em :" + em.toString());
		return em.find(entityClass, entityID);
	}
	
	@Override
	public void detach(T entity) {
		em.detach(entity);
	}
	

	// car jpa ne possede pas de methode
	// em.getCriteriaBuilder().createQuery()<T> method
	@Override
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public List<T> findAll() {
		CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
		cq.select(cq.from(entityClass));
		return em.createQuery(cq).getResultList();
	}

	// car jpa ne possede pas de methode
	// ery.getSingleResult()<T> method
	@Override
	@SuppressWarnings("unchecked")
	public T findOneResult(String namedQuery, Map<String, Object> parameters) {
		T result = null;

		try {
			Query query = em.createNamedQuery(namedQuery);

			// ssi parametres pas null et non vide
			if (parameters != null && !parameters.isEmpty()) {
				populateQueryParameters(query, parameters);
			}

			result = (T) query.getSingleResult();

		} catch (Exception e) {
			log.debug("Error dans la methode findOneResult : " + e.getMessage());
			e.printStackTrace();
		}

		return result;
	}

	private static void populateQueryParameters(Query query,
			Map<String, Object> parameters) {

		for (Entry<String, Object> entry : parameters.entrySet()) {
			query.setParameter(entry.getKey(), entry.getValue());
		}
	}
}
